package com.bitcarton.dynamic.datasource.autoconfigure;

import com.bitcarton.dynamic.datasource.autoconfigure.dynamic.ConstantData;
import com.bitcarton.dynamic.datasource.autoconfigure.dynamic.annotation.DynamicDs;
import com.bitcarton.dynamic.datasource.autoconfigure.dynamic.datasource.DynamicDatasource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author wwd
 */
@Configuration
@Order(1)
public class MethodAroundAdvice implements MethodBeforeAdvice, AfterReturningAdvice {
    private static final Logger log = LoggerFactory.getLogger(MethodAroundAdvice.class);

    private final static SimpleDateFormat SD = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final ThreadLocal<Long> THREAD_LOCAL_TIME = new ThreadLocal<>();

    @Override
    public void before(Method method, Object[] args, Object target) {
        if (ConstantData.TO_STRING.equals(method.getName())) {
            return;
        }

        String mapperName = TargetUtil.getTarget(target);
        Class<?> aClassList = null;
        try {
            aClassList = Class.forName(mapperName);
            DynamicDs annotation =  aClassList.getAnnotation(DynamicDs.class);
            if (null != annotation && StringUtils.isNotBlank(annotation.name())) {
                DynamicDatasource.setDataSource(annotation.name());
            }
        } catch (Exception e) {
            log.error("before error", e);
        }
        log.info("method:{}.{} begin start,dataSource is {},time at {}", method.getDeclaringClass().getName(), method.getName(), DynamicDatasource.getDataSource(), SD.format(new Date()));
        THREAD_LOCAL_TIME.set(System.currentTimeMillis());
    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) {
        if (ConstantData.TO_STRING.equals(method.getName())) {
            return;
        }
        long start = THREAD_LOCAL_TIME.get();
        long end = System.currentTimeMillis();
        log.info("method:{}.{} end,dataSource = {} ,cost {} ms", method.getDeclaringClass().getName(), method.getName(), DynamicDatasource.getDataSource(), end - start);
        THREAD_LOCAL_TIME.remove();
        DynamicDatasource.clearDataSource();
    }


}